package com.sq.subject.domain.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.CollectionUtil;
import com.alibaba.fastjson2.JSON;
import com.sq.subject.domain.bo.CategoryAndLabelBO;
import com.sq.subject.domain.bo.SubjectLabelBO;
import com.sq.subject.domain.bo.PrimaryCategoryBO;
import com.sq.subject.domain.bo.SubjectCategoryBO;
import com.sq.subject.domain.convert.SubjectCategoryConverter;
import com.sq.subject.infra.basic.entity.SubjectCategory;
import com.sq.subject.infra.basic.entity.SubjectLabel;
import com.sq.subject.infra.basic.entity.SubjectMapping;
import com.sq.subject.infra.basic.service.SubjectCategoryService;
import com.sq.subject.domain.service.SubjectCategoryDomainService;
import com.sq.subject.infra.basic.service.SubjectLabelService;
import com.sq.subject.infra.basic.service.SubjectMappingService;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.stream.Collectors;

import static java.util.concurrent.CompletableFuture.runAsync;

/**
 * @author quan
 */
@Service
@Slf4j
public class SubjectCategoryDomainServiceImpl implements SubjectCategoryDomainService {

    @Resource
    private SubjectCategoryService subjectCategoryService;

    @Resource
    private SubjectLabelService subjectLabService;

    @Resource
    private SubjectMappingService subjectMappingService;

    @Resource
    private ThreadPoolExecutor threadPoolExecutor;
    @Override
    public void add(SubjectCategoryBO subjectCategoryBO) {
        if(log.isInfoEnabled()){
            log.info("SubjectCategoryDomainServiceImpl.add.bo：{}", JSON.toJSONString(subjectCategoryBO));
        }
        SubjectCategory subjectCategory = SubjectCategoryConverter.INSTANCE.convertBoToSubjectCategory(subjectCategoryBO);
        subjectCategoryService.insert(subjectCategory);
    }

    @Override
    public void update(SubjectCategoryBO subjectCategoryBO) {
        if(log.isInfoEnabled()){
            log.info("SubjectCategoryDomainServiceImpl.update.bo：{}", JSON.toJSONString(subjectCategoryBO));
        }
        SubjectCategory subjectCategory = SubjectCategoryConverter.INSTANCE.convertBoToSubjectCategory(subjectCategoryBO);
        subjectCategoryService.update(subjectCategory);
    }

    @Override
    public List<PrimaryCategoryBO> querySubjectPrimaryCategoryCategory() {
        SubjectCategory subjectCategory = new SubjectCategory();
        subjectCategory.setParentId(0L);
        List<SubjectCategory> primaryCategoryList = subjectCategoryService.queryByCondition(subjectCategory);
        List<PrimaryCategoryBO> primaryCategoryBOList = BeanUtil.copyToList(primaryCategoryList, PrimaryCategoryBO.class);
        if(log.isInfoEnabled()){
            log.info("SubjectCategoryDomainServiceImpl.querySubjectPrimaryCategoryCategory.boList：{}", JSON.toJSONString(primaryCategoryBOList));
        }
        return primaryCategoryBOList;
    }

    @Override
    public List<SubjectCategoryBO> queryCategoryByPrimary(SubjectCategoryBO subjectCategoryBO) {
        SubjectCategory subjectCategory = new SubjectCategory();
        subjectCategory.setParentId(subjectCategoryBO.getId());
        List<SubjectCategory> categoryList = subjectCategoryService.queryByCondition(subjectCategory);
        List<SubjectCategoryBO> subjectCategoryBOList = BeanUtil.copyToList(categoryList, SubjectCategoryBO.class);
        if(log.isInfoEnabled()){
            log.info("SubjectCategoryDomainServiceImpl.queryCategoryByPrimary.boList：{}", JSON.toJSONString(subjectCategoryBOList));
        }
        return subjectCategoryBOList;
    }

    @Override
    public List<CategoryAndLabelBO> queryCategoryAndLabel(SubjectCategoryBO subjectCategoryBO) throws ExecutionException, InterruptedException {
        if(log.isInfoEnabled()){
            log.info("SubjectCategoryDomainServiceImpl.queryCategoryAndLabel.bo：{}", JSON.toJSONString(subjectCategoryBO));
        }
        List<SubjectCategoryBO> subjectCategoryBOList = queryCategoryByPrimary(subjectCategoryBO);
        if(CollectionUtil.isEmpty(subjectCategoryBOList)){
            return new ArrayList<>();
        }
//        List<FutureTask<Map<Long,List<SubjectLabelBO>>>> futureTaskList = new ArrayList<>();
//        subjectCategoryBOList.forEach(bo ->{
//                FutureTask<Map<Long, List<SubjectLabelBO>>> labelListTask = new FutureTask<>(() -> {
//                            Map<Long, List<SubjectLabelBO>> labelMap = getCategoryAndLabelBO(bo);
//                            return labelMap;
//                        });
//                threadPoolExecutor.submit(labelListTask);
//                futureTaskList.add(labelListTask);
//                }
//        );
        List<CompletableFuture<Map<Long,List<SubjectLabelBO>>>> completableFutureList = subjectCategoryBOList.stream().map(bo ->
            CompletableFuture.supplyAsync(() -> getCategoryAndLabelBO(bo), threadPoolExecutor)).toList();

        Map<Long, List<SubjectLabelBO>> labelMap = new HashMap<>();
//        for (FutureTask<Map<Long, List<SubjectLabelBO>>> mapFutureTask : futureTaskList) {
//            Map<Long, List<SubjectLabelBO>> map = mapFutureTask.get();
//            if(CollUtil.isEmpty(map)){
//                continue;
//            }
//            labelMap.putAll(map);
//        }
        for (CompletableFuture<Map<Long, List<SubjectLabelBO>>> mapCompletableFuture : completableFutureList) {
            Map<Long, List<SubjectLabelBO>> map = mapCompletableFuture.get();
            if(CollUtil.isEmpty(map)){
                continue;
            }
            labelMap.putAll(map);
        }
        for(CompletableFuture future : completableFutureList){
            Map<Long, List<SubjectLabelBO>> map = (Map<Long, List<SubjectLabelBO>>) future.get();
            labelMap.putAll(map);
        }
        List<CategoryAndLabelBO> categoryAndLabelBOList = BeanUtil.copyToList(subjectCategoryBOList, CategoryAndLabelBO.class);
        categoryAndLabelBOList.forEach(
                categoryAndLabelBO -> {
                    List<SubjectLabelBO> labelBOList = labelMap.get(categoryAndLabelBO.getId());
                    categoryAndLabelBO.setLabelBOList(labelBOList);
                }
        );
        if(log.isInfoEnabled()){
            log.info("SubjectCategoryDomainServiceImpl.queryCategoryByPrimary.boList：{}", JSON.toJSONString(categoryAndLabelBOList));
        }
        return categoryAndLabelBOList;
    }

    private Map<Long,List<SubjectLabelBO>> getCategoryAndLabelBO(SubjectCategoryBO bo) {
        Map<Long,List<SubjectLabelBO>> labelMap = new HashMap();
        CategoryAndLabelBO categoryAndLabelBO = BeanUtil.copyProperties(bo, CategoryAndLabelBO.class);
        SubjectMapping subjectMapping = new SubjectMapping();
        subjectMapping.setCategoryId(bo.getId());
        List<SubjectMapping> subjectMappingList = subjectMappingService.queryByCondition(subjectMapping);
        if(CollUtil.isEmpty(subjectMappingList)){
            categoryAndLabelBO.setLabelBOList(new ArrayList<>());
        }
        List<Long> labelIds = subjectMappingList.stream().map(SubjectMapping::getLabelId).toList();
        List<SubjectLabel> subjectLabelList = subjectLabService.batchQueryById(labelIds);
        List<SubjectLabelBO> labelBOList = BeanUtil.copyToList(subjectLabelList, SubjectLabelBO.class);
        labelMap.put(bo.getId(),labelBOList);
        return labelMap;
    }

    @Override
    public void delete(SubjectCategoryBO subjectCategoryBO) {
        if(log.isInfoEnabled()){
            log.info("SubjectCategoryDomainServiceImpl.delete.bo：{}", JSON.toJSONString(subjectCategoryBO));
        }
        subjectCategoryService.deleteById(subjectCategoryBO.getId());
    }
}
